package com.itbaizhan.shopping_category_service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itbaizhan.shopping_category_service.mapper.CategoryMapper;
import com.itbaizhan.shopping_common.pojo.Category;
import com.itbaizhan.shopping_common.service.CategoryService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@DubboService
@Transactional
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void add(Category category) {
        categoryMapper.insert(category);
        refreshRedisCategory();
    }

    @Override
    public void update(Category category) {
        categoryMapper.updateById(category);
        refreshRedisCategory();
    }

    @Override
    public void delete(Long[] ids) {
        categoryMapper.deleteBatchIds(Arrays.asList(ids));
        refreshRedisCategory();
    }

    @Override
    public void putAway(long id, int status) {
        Category category = categoryMapper.selectById(id);
        category.setStatus(status);
        categoryMapper.updateById(category);
        refreshRedisCategory();
    }

    @Override
    public Category findById(long id) {
        return categoryMapper.selectById(id);
    }

    @Override
    public List<Category> findAll() {
        // 1、先从redis缓存中查询
        ListOperations<String,Category> listOperations = redisTemplate.opsForList();
        List<Category> categories = listOperations.range("categories", 0, -1);
        if(categories != null && categories.size() > 0) {
            System.out.println("从redis查询");
            return  categories;
        }
        // 2、尝试获取分布式锁（避免因缓存失效导致大量用户同时访问数据库：缓存击穿问题
        String lockKey = "categories_lock";
        boolean locked = false;
        try {
            // 尝试获取锁，设置过期时间防止死锁
            locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 30, TimeUnit.SECONDS);

            if (locked) {
                // 获取锁成功，再次检查缓存（双重检查）
                categories = listOperations.range("categories", 0, -1);
                if(categories != null && categories.size() > 0) {
                    return categories;
                }

                // 从数据库查询
                System.out.println("从mysql查询");
                QueryWrapper<Category> wrapper = new QueryWrapper<>();
                wrapper.eq("status", 1);
                List<Category> categoryList = categoryMapper.selectList(wrapper);

                // 更新缓存
                listOperations.leftPushAll("categories", categoryList);
                return categoryList;
            } else {
                // 未获取到锁，等待并重试
                Thread.sleep(100); // 短暂等待
                return findAll(); // 递归调用（注意设置最大重试次数）
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("查询中断", e);
        } finally {
            if (locked) {
                redisTemplate.delete(lockKey); // 释放锁
            }
        }
    }

    @Override
    public Page<Category> search(int page, int size) {
        return categoryMapper.selectPage(new Page(page, size), null);
    }

    /**
     * 更新redis中的广告数据
     */
    public void refreshRedisCategory() {
        //从数据库查询广告
        QueryWrapper<Category> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1);
        List<Category> categoryList = categoryMapper.selectList(wrapper);

        //删除缓存中原有的
        redisTemplate.delete("categories");
        // 将新的广告数据同步到redis中
        redisTemplate.opsForList().leftPushAll("categories", categoryList);
    }
}
